package
{
	import flash.display.*;
	import flash.errors.IllegalOperationError;
	import flash.events.Event;
	import flash.geom.Point;

	/** This tool is used to outline a closed polygon for the game */
	public class OutlineTool extends CursorTool
	{
		// STATIC PUBLIC CONSTS
		public static const CURSOR_RADIUS:Number = 8;
		// private objects
		private var cursor:Sprite = null;
		private var outliningPoints:Array, projectingPoints:Array;
		private var firstPoint:DrawPoint, previousPoint:DrawPoint;
		
		override public function get components():Array{return outliningPoints;}
		public function OutlineTool()
		{
			super(this);
			outliningPoints = new Array();
			projectingPoints = new Array();
			this.addEventListener(Event.ADDED, handleAdded);
		}
		private function handleAdded(event:Event):void
		{
			this.removeEventListener(Event.ADDED, handleAdded);
			drawCursor();
			this.addEventListener(Event.REMOVED, handleRemoved);			
		}
		
		/** Utilizes the process of selecting points, check to make sure they are not already selected
		 * If selected, deselect them and everything that follows them.
		 * If unselected, select them.  If returning to first point, close and dispatch a complete event */
		override public function selectComponent(c:MovieClip):void
		{
			var _p:DrawPoint, newpoint:DrawPoint;
			var _s:DrawSegment;
			var found:Boolean;
			var i:int;
			
			var p:DrawPoint = DrawPoint(c);
			// is this point already selected?
			if (p.outlining && !p.projecting)
			{ /// YES, deselect
				// remove any projecting points
				for each (_p in projectingPoints)
				{
					_p.project = false;
				}
				projectingPoints = new Array();
				
				// get index of this point in points array
				var pi:uint = outliningPoints.indexOf(p);
				// go through each point up to and including p and deselect
				for (i=outliningPoints.length-1; i >= pi; i--)
				{
					_p = outliningPoints.splice(i, 1)[0];
					_p.outline = false;
					// remove segment between this point and the previous
					for each (_s in _p.drawSegments)
					{
						_s.outline = false;
					}
				}
				// with the last remaining point in the array, re-project
				if (outliningPoints.length > 0)
				{
					p = outliningPoints[outliningPoints.length-1];
					for each (_s in p.drawSegments)
					{								
						if (_s.point1 != p){ newpoint = _s.point1 }
						else if (_s.point2 != p){ newpoint = _s.point2 }
						else { trace("shouldn't happen");}
						// loop through the points already outlined and make sure that this is not one of them, if not add to list
						found = false;
						for each (_p in outliningPoints)
						{
							//trace(newpoint.point, firstPoint.point, previousPoint.point);
							//if ( (newpoint == _p && newpoint != firstPoint) || newpoint == previousPoint)
							if (newpoint == _p)
							{
								found = true; break;
							}
						}
						if (!found)
						{
							newpoint.project = true;
							projectingPoints.push(newpoint);									
						} else 
						{
							// nothing here, just means we already have this point on the array
						}
					}
					previousPoint = p;
				}
				
			} else
			{ // No, add this point
				// different rules for the first point
				if (outliningPoints.length == 0)
				{
					this.firstPoint = p;
					p.outline = true;
					outliningPoints.push(p);
					// add all points on segments attached to this point to projected list
					projectingPoints = new Array();
					for each (_s in p.drawSegments)
					{						
						if (_s.point1 != p){ newpoint = _s.point1 }
						else if (_s.point2 != p){ newpoint = _s.point2 }
						newpoint.project = true;
						projectingPoints.push(newpoint);						
					}
					previousPoint = p;
				} else
				{			
					found = false;
					// make sure that this point is on the projected array
					for each (_p in projectingPoints)
					{
						if (p == _p)
						{
							found = true; break;
						}
					}
					// if this point is on the projected list, create a new projected list and highlight segment in between
					if (found)
					{
						// go through segments on this point, looking for previous point, that's the segment to highlight
						found = false;
						for each (_s in p.drawSegments)
						{
							if (_s.point1 == previousPoint || _s.point2 == previousPoint)
							{
								found = true; break;								
							}
						}
						if (found)
						{
							_s.outline = true;	
							// go through previous projected points and unhighlight
							for each (_p in projectingPoints)
							{
								_p.project = false;
							}
							/// if this is point closes the loop, end it
							if (p == firstPoint)
							{
								this.dispatchEvent(new Event(Event.COMPLETE));
							} else
							{
							
								p.outline = true; // outline this
								outliningPoints.push(p);						
								
								// go though each of the segments attached to this new point to get projected points
								projectingPoints = new Array();
								for each (_s in p.drawSegments)
								{								
									if (_s.point1 != p){ newpoint = _s.point1 }
									else if (_s.point2 != p){ newpoint = _s.point2 }
									else { trace("shouldn't happen");}
									// loop through the points already outlined and make sure that this is not one of them, if not add to list
									found = false;
									for each (_p in outliningPoints)
									{
										//trace(newpoint.point, firstPoint.point, previousPoint.point);
										if ( (newpoint == _p && newpoint != firstPoint) || newpoint == previousPoint)
										{
											found = true; break;
										}
									}
									if (!found)
									{
										newpoint.project = true;
										projectingPoints.push(newpoint);									
									} else 
									{
										// nothing here, just means we already have this point on the array
									}
								}
								previousPoint = p;
							}
						} else 
						{ // unconnected to previous point
							trace("problem 1");
							DrawingItem(parent.parent).newMessage(p.parent, "That point isn't connected to the last point",  p.x+50, p.y-50, MessageBox.EPHEMERAL_TYPE);
						}
					}  else 
					{ // unconnected to previous point
						trace("problem 2");
						DrawingItem(parent.parent).newMessage(p.parent, "That point isn't connected to the last point",  p.x+50, p.y-50, MessageBox.EPHEMERAL_TYPE);
					}
				}
			}
		}
		override public function clearComponent(c:MovieClip):void
		{
			var p:DrawPoint = DrawPoint(c);
			// run through points and make sure this component is in the array
			for (var i:int=0; i < outliningPoints.length; i++)
			{
				var _p:DrawPoint = outliningPoints[i];
				if (p == _p)
				{
					p.outline = false;
					// go through all segments and clear them (the segments will take care of it if they are already clear
					for each (var s:DrawSegment in p.drawSegments)
					{
						s.outline = false;
					}
					outliningPoints.splice(i,1);
				}
			}
		}
		override public function process(point:Point, component:MovieClip=null):Point
		{
			this.x = point.x;
			this.y = point.y;
			return point;
		}
		
		////////////////////////// PRIVATE FUNCTIONS ///////////////////////
		/** Draw the cursor representation */
		private function drawCursor ():void
		{
			if (cursor == null)
			{
				cursor = new Sprite();
				this.addChild(cursor);
			} else
			{
				cursor.graphics.clear();
			}
			if (true)
			{
				cursor.graphics.lineStyle(2, 0x0000FF);
				cursor.graphics.drawCircle(0,0,CURSOR_RADIUS);
			}
		}
		/** On removal unproject and unoutline */
		private function handleRemoved(event:Event):void
		{
			this.removeEventListener(Event.REMOVED, handleRemoved);
			for each (var dp:DrawPoint in this.outliningPoints)
			{
				dp.outline = false;
				for each (var s:DrawSegment in dp.drawSegments)
				{
					s.outline = false;
				}
			}
			for each (dp in this.projectingPoints)
			{
				dp.project = false;
			}
		}
	}
}